// ФАЙЛ: app.module.ts
 import { Module } from '@nestjs/common';
import { PrismaModule } from './prisma/prisma.module';
import { UsersModule } from './users/users.module';
import { AuthModule } from './auth/auth.module';
import { ItemsModule } from './items/items.module';
import { OrdersModule } from './orders/orders.module';
import { NestjsFormDataModule } from 'nestjs-form-data';

@Module({
  imports: [
    PrismaModule,
    UsersModule,
    AuthModule,
    ItemsModule,
    OrdersModule,
    NestjsFormDataModule,
  ],
})
export class AppModule {}

// ФАЙЛ: main.ts
 import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ZodValidationPipe } from 'nestjs-zod';
import { json } from 'stream/consumers';
import * as bodyParser from 'body-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.enableCors({
    origin: '*',
    methods: '*',
  });

  app.use(bodyParser.json({ limit: '50mb' }));
  app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));

  app.useGlobalPipes(new ZodValidationPipe());
  await app.listen(3005);
}
bootstrap();

// ФАЙЛ: auth\auth.controller.ts
 import { Body, Controller, Get, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LoginDto } from 'src/users/dtos/login';
import { UserCreateDto } from 'src/users/dtos/signup';
import { $Enums } from '@prisma/client';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('/sign-up')
  async signUp(@Body() userDto: UserCreateDto) {
    const { accessToken } = await this.authService.signUp({
      ...userDto,
      role: $Enums.Role.USER,
    });

    return { accessToken };
  }

  @Post('/sign-in')
  async signIn(@Body() userDto: LoginDto) {
    const { accessToken } = await this.authService.signIn(userDto);

    return { accessToken };
  }
}

// ФАЙЛ: auth\auth.module.ts
 import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { JwtModule } from '@nestjs/jwt';
import { UsersModule } from 'src/users/users.module';
import { AuthController } from './auth.controller';

@Module({
  providers: [AuthService],
  controllers: [AuthController],
  imports: [JwtModule, UsersModule],
})
export class AuthModule {}

// ФАЙЛ: auth\auth.service.ts
 import {
  BadRequestException,
  ConflictException,
  Injectable,
  Logger,
  NotFoundException,
} from '@nestjs/common';
import { UserCreateDto } from 'src/users/dtos/signup';
import { UsersService } from 'src/users/users.service';
import { hash, compare } from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
import { $Enums } from '@prisma/client';
import { LoginDto } from 'src/users/dtos/login';

const SALT = Number('smetanina');

@Injectable()
export class AuthService {
  private readonly logger = new Logger('AuthService');

  constructor(
    private readonly usersService: UsersService,
    private readonly jwtService: JwtService,
  ) {}

  async signUp(dto: UserCreateDto) {
    if (!!(await this.usersService.findByEmail(dto.email))) {
      this.logger.debug(`User with email ${dto.email} already exists`);
      throw new ConflictException('Р­РјР°РёР» СѓР¶Рµ Р·Р°СЂРµРіРёСЃС‚СЂРёСЂРѕРІР°РЅ');
    }

    this.logger.verbose('signing up user', dto);

    const hashPassword = await hash(dto.password, SALT);

    await this.usersService.create({
      ...dto,
      password: hashPassword,
      role: dto.role,
    });

    const user = await this.usersService.findByEmail(dto.email);

    return await this.generateTokens(user.id, user.email, user.role);
  }

  async signIn(dto: LoginDto) {
    const user = await this.usersService.findByEmail(dto.email);

    if (!user) {
      this.logger.debug(`user not found, user=${JSON.stringify(dto)}`);
      throw new NotFoundException('РџРѕР»СЊР·РѕРІР°С‚РµР»СЊ РЅРµ РЅР°Р№РґРµРЅ');
    }

    if (!(await compare(dto.password, user.password))) {
      this.logger.debug(
        `invalid password user=${JSON.stringify(dto)} user.password=${
          user.password
        }`,
      );
      throw new BadRequestException('РќРµРІРµСЂРЅС‹Рµ РґР°РЅРЅС‹Рµ');
    }

    return await this.generateTokens(user.id, user.email, user.role);
  }

  async generateTokens(id: number, email: string, role: $Enums.Role) {
    this.logger.verbose('generating tokens');

    const accessToken = await this.jwtService.signAsync(
      {
        id,
        email,
        role,
      },
      {
        secret: 'smetanina_secret',
        expiresIn: '365d',
      },
    );

    return {
      accessToken,
    };
  }
}

// ФАЙЛ: auth\decorators\auth.decorator.ts
 import { SetMetadata, UseGuards, applyDecorators } from '@nestjs/common';
import { AuthGuard } from '../guards/auth.guard';
import { Role } from '@prisma/client';
import { RoleGuard } from '../guards/role.guard';

export const ROLES_METADATA = 'roles-metadata';

export const RequiredAuth = (...roles: Role[]) =>
  applyDecorators(
    roles.length > 0
      ? applyDecorators(
          SetMetadata(ROLES_METADATA, roles),
          UseGuards(AuthGuard, RoleGuard),
        )
      : UseGuards(AuthGuard),
  );

// ФАЙЛ: auth\decorators\user.decorator.ts
 import { ExecutionContext, createParamDecorator } from '@nestjs/common';
import { UserClaims } from 'src/shared/user';

export const User = createParamDecorator(
  (key: keyof UserClaims, ctx: ExecutionContext) => {
    const req = ctx.switchToHttp().getRequest();
    const user = req.user;
    return key ? user[key] : user;
  },
);

// ФАЙЛ: auth\guards\auth.guard.ts
 import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request: Request = context.switchToHttp().getRequest();
    const token = this.extractToken(request);
    if (!token) {
      throw new UnauthorizedException();
    }

    try {
      const claims = await this.jwtService.verifyAsync(token, {
        secret: 'smetanina_secret',
      });

      request['user'] = claims;
    } catch (error) {
      console.log(error);
      throw new UnauthorizedException();
    }

    return true;
  }

  private extractToken(request: Request): string | undefined {
    const [type, token] = request.headers['authorization']?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}

// ФАЙЛ: auth\guards\role.guard.ts
 import {
  CanActivate,
  ExecutionContext,
  Injectable,
  Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ROLES_METADATA } from '../decorators/auth.decorator';

@Injectable()
export class RoleGuard implements CanActivate {
  private readonly logger = new Logger('RoleGuard');

  constructor(private readonly reflector: Reflector) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const requiredRoles = this.reflector.getAllAndOverride<string[]>(
      ROLES_METADATA,
      [context.getHandler(), context.getClass()],
    );

    if (!requiredRoles) {
      this.logger.verbose('roles dont specified');
      return true;
    }

    const request: Request = context.switchToHttp().getRequest();
    const user = request['user'];

    this.logger.verbose('checking role permissions', {
      requiredRoles,
      userRole: user.role,
    });
    return requiredRoles.includes(user.role);
  }
}

// ФАЙЛ: items\items.controller.ts
 import {
  BadRequestException,
  Body,
  Controller,
  Delete,
  Get,
  HttpException,
  HttpStatus,
  InternalServerErrorException,
  Param,
  ParseIntPipe,
  Post,
  Put,
  Query,
} from '@nestjs/common';
import { ItemsService } from './items.service';
import { GetItemsByIdsDto, ItemDto } from './dto/items';
import { FormDataRequest } from 'nestjs-form-data';
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';

@Controller('items')
export class ItemsController {
  constructor(private readonly itemsService: ItemsService) {}

  @Get()
  async getAllItems(@Query('page') page: number) {
    return await this.itemsService.getAllItems(page);
  }

  @Post('/categories')
  async createCategory(@Query('name') name: string) {
    const category = await this.itemsService.createCategory(name);

    return category;
  }

  @Get('/categories')
  async getAllCategories() {
    const categories = await this.itemsService.getAllCategories();

    return categories;
  }

  @Delete('/categories/:id')
  async deleteCategory(@Param('id', new ParseIntPipe()) id: number) {
    try {
      const count = await this.itemsService.deleteCategoryById(id);
      return { count };
    } catch (error) {
      if (error instanceof PrismaClientKnownRequestError)
        throw new HttpException(
          'РџРѕР·РёС†РёРё РїСЂРёРІСЏР·Р°РЅС‹ Рє СЌС‚РѕР№ РєР°С‚РµРіРѕСЂРёРё',
          HttpStatus.BAD_REQUEST,
        );

      throw new BadRequestException();
    }
  }

  @Post('/ids')
  async getAllItemsByIds(@Body() dto: GetItemsByIdsDto) {
    const items = await this.itemsService.getItemsByIds(dto.ids);

    return items;
  }

  @Post()
  @FormDataRequest()
  async createItem(@Body() dto: ItemDto) {
    const id = await this.itemsService.createItem(dto, dto.file);
    console.log('created item + ', id);
    return { id };
  }

  @Get('/categories/:id')
  async getItemsByCategoryId(@Param('id', new ParseIntPipe()) id: number) {
    const items = await this.itemsService.getByCategoryId(id);

    return items.map((item) => ({
      ...item,
      photo: item.photo.toString('base64'),
    }));
  }

  @Get('/:id')
  async getItemById(@Param('id', new ParseIntPipe()) id: number) {
    const item = await this.itemsService.getItemById(id);

    return { ...item, photo: item.photo.toString('base64') };
  }

  @Delete('/:id')
  async deleteItem(@Param('id', new ParseIntPipe()) id: number) {
    return await this.itemsService.deleteItemById(id);
  }

  @Put('/:id')
  @FormDataRequest()
  async updateItem(
    @Param('id', new ParseIntPipe()) id: number,
    @Body() dto: ItemDto,
  ) {
    const _ = await this.itemsService.updateItemById(id, dto, dto.file);

    return {};
  }
}

// ФАЙЛ: items\items.module.ts
 import { Module } from '@nestjs/common';
import { ItemsService } from './items.service';
import { ItemsController } from './items.controller';
import { PrismaModule } from 'src/prisma/prisma.module';
import { NestjsFormDataModule } from 'nestjs-form-data';

@Module({
  providers: [ItemsService],
  imports: [PrismaModule, NestjsFormDataModule],
  controllers: [ItemsController],
})
export class ItemsModule {}

// ФАЙЛ: items\items.service.ts
 import { Injectable, Logger } from '@nestjs/common';
import { Item } from '@prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';
import { ItemDto, WithoutFileDto } from './dto/items';
import { MemoryStoredFile } from 'nestjs-form-data';

@Injectable()
export class ItemsService {
  private readonly logger = new Logger('itemsService');
  constructor(private readonly prisma: PrismaService) {}

  async deleteItemById(id: number) {
    return this.prisma.item.delete({ where: { id } });
  }

  async getAllItems(page: number = 0) {
    const pageSize = 200;
    return this.prisma.item.findMany({
      take: pageSize,
      select: {
        id: true,
        name: true,
        description: true,
        category: true,
        price: true,
      },
      skip: page * pageSize,
    });
  }

  async createCategory(categoryName: string) {
    return this.prisma.itemCategory.create({ data: { name: categoryName } });
  }

  async getByCategoryId(categoryId: number) {
    const items = await this.prisma.item.findMany({
      where: {
        categoryId,
      },
    });

    return items;
  }

  async getItemsByIds(ids: number[]) {
    const items = await this.prisma.item.findMany({
      where: {
        id: {
          in: ids,
        },
      },
      select: {
        id: true,
        name: true,
        description: true,
        category: true,
        price: true,
      },
    });

    return items;
  }

  async deleteCategoryById(id: number) {
    return this.prisma.itemCategory.delete({ where: { id } });
  }

  async getAllCategories() {
    const categories = await this.prisma.itemCategory.findMany();

    return categories;
  }

  async getItemById(id: number) {
    return this.prisma.$transaction(async (tx) => {
      const item = await this.prisma.item.findUnique({
        where: { id },
        include: { category: true },
      });

      const now = new Date();
      const oneMonthAgo = new Date();
      oneMonthAgo.setMonth(now.getMonth() - 1);
      const m = {};

      const orderItems = await this.prisma.orderItem.findMany({
        where: {
          menuItemId: id,
          order: {
            createdAt: {
              gte: oneMonthAgo,
            },
          },
        },
        include: { order: true },
      });

      orderItems.forEach((item) => {
        const date = item.order.createdAt;
        const day = String(date.getDate()).padStart(2, '0');
        const month = String(date.getMonth() + 1).padStart(2, '0'); // РњРµСЃСЏС†С‹ РІ JS РЅР°С‡РёРЅР°СЋС‚СЃСЏ СЃ 0
        const year = date.getFullYear();
        const finalDate = `${day}.${month}.${year}`;

        if (m[finalDate]) {
          m[finalDate] += 1;
        } else {
          m[finalDate] = 1;
        }
      });

      return { ...item, stat: m };
    });
  }

  async createItem(dto: WithoutFileDto, photo?: MemoryStoredFile) {
    const d = {
      ...dto,
      price: dto.price && Number.parseFloat(dto.price),
      categoryId: Number.parseInt(dto.categoryId),
      photo: photo.buffer,
      file: undefined,
    };

    const item = await this.prisma.item.create({
      data: {
        ...d,
        categoryId: d.categoryId,
      },
      select: { id: true },
    });

    return item.id;
  }

  async updateItemById(
    id: number,
    dto: Partial<WithoutFileDto>,
    photo?: MemoryStoredFile,
  ) {
    const data = {
      ...dto,
      price: dto.price && Number.parseFloat(dto.price),
      categoryId: Number.parseInt(dto.categoryId),
      photo: photo ? photo.buffer : undefined,
      file: undefined,
    };

    await this.prisma.item.update({
      where: { id },
      data: {
        ...data,
        categoryId: undefined,
      },
    });

    if (data.categoryId)
      await this.prisma.item.update({
        where: { id },
        data: {
          category: {
            connect: { id: data.categoryId },
          },
        },
      });
  }
}

// ФАЙЛ: items\dto\items.ts
 import { OmitType } from '@nestjs/mapped-types';
import { IsFile, MemoryStoredFile } from 'nestjs-form-data';
import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';

export const GetItemsByIdsRequestSchema = z.object({
  ids: z.array(z.number()).default([]),
});

export type GetItemsByIdsRequest = z.infer<typeof GetItemsByIdsRequestSchema>;
export class GetItemsByIdsDto extends createZodDto(
  GetItemsByIdsRequestSchema,
) {}

export class ItemDto {
  @IsFile()
  file: MemoryStoredFile;

  description: string;
  name: string;
  price: string;
  categoryId: string;
}

export class WithoutFileDto extends OmitType(ItemDto, ['file']) {}

// ФАЙЛ: orders\orders.controller.ts
 import {
  Body,
  Controller,
  Get,
  Param,
  ParseIntPipe,
  Post,
  Put,
  Query,
  Req,
} from '@nestjs/common';
import { OrdersService } from './orders.service';
import { CreateOrderDto } from './dto/create';
import { RequiredAuth } from 'src/auth/decorators/auth.decorator';
import { User } from 'src/auth/decorators/user.decorator';
import { UserClaims } from 'src/shared/user';
import { $Enums, OrderStatus } from '@prisma/client';

@Controller('orders')
export class OrdersController {
  constructor(private readonly ordersService: OrdersService) {}

  @Post()
  @RequiredAuth()
  async create(@Body() body: CreateOrderDto, @User() { id }: UserClaims) {
    const count = await this.ordersService.create(id, body);

    return count;
  }

  @Get()
  @RequiredAuth()
  async getMyOrders(@User() { id }: UserClaims) {
    const orders = await this.ordersService.getOrderByUserId(id);

    return orders;
  }

  @Get('/all')
  @RequiredAuth()
  async getAllOrders(@Query('status') status?: $Enums.OrderStatus) {
    const orders = await this.ordersService.getAllOrders(status);

    return orders;
  }

  @Put('/:id')
  @RequiredAuth()
  async changeOrderStatus(
    @Param('id', new ParseIntPipe()) id: number,
    @Query('status') status: $Enums.OrderStatus,
  ) {
    const item = await this.ordersService.changeOrderStatus(id, status);

    return item;
  }

  @Get('/:id')
  @RequiredAuth()
  async getOrderItems(@Param('id', new ParseIntPipe()) id: number) {
    const items = await this.ordersService.getOrderItems(id);

    return items;
  }
}

// ФАЙЛ: orders\orders.module.ts
 import { Module } from '@nestjs/common';
import { OrdersService } from './orders.service';
import { OrdersController } from './orders.controller';
import { PrismaModule } from 'src/prisma/prisma.module';
import { JwtModule } from '@nestjs/jwt';

@Module({
  providers: [OrdersService],
  imports: [PrismaModule, JwtModule],
  controllers: [OrdersController],
})
export class OrdersModule {}

// ФАЙЛ: orders\orders.service.ts
 import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateOrderDto } from './dto/create';
import { $Enums, OrderItem } from '@prisma/client';
import { getCurrentDate } from 'src/utils/date';

@Injectable()
export class OrdersService {
  constructor(private readonly prisma: PrismaService) {}

  async create(userId: number, dto: CreateOrderDto) {
    return this.prisma.$transaction(async (tx) => {
      const order = await this.prisma.order.create({
        data: {
          address: dto.address,
          count: dto.count,
          description: dto.description,
          user: { connect: { id: userId } },
          createdAt: getCurrentDate(),
        },
      });

      const items = await this.prisma.orderItem.createMany({
        data: dto.items.map((item) => ({
          orderId: order.id,
          menuItemId: item.id,
          quantity: item.quantity,
        })),
      });

      return items.count;
    });
  }

  async changeOrderStatus(orderId: number, status: $Enums.OrderStatus) {
    return this.prisma.order.update({
      where: { id: orderId },
      data: { status: status },
    });
  }

  async getAllOrders(status?: $Enums.OrderStatus) {
    return this.prisma.$transaction(async (tx) => {
      const orders = await this.prisma.order.findMany({
        where: { status },
        orderBy: { createdAt: 'desc' },
        include: { user: true },
      });

      return Promise.all(
        orders.map(async (order) => {
          const products = await this.prisma.orderItem.findMany({
            where: { orderId: order.id },
            include: {
              menuItem: true,
            },
          });

          return {
            ...order,
            productCount: products.length,
            sum: products.reduce(
              (acc, item) =>
                acc + item.menuItem.price.toNumber() * item.quantity,
              0,
            ),
          };
        }),
      );
    });
  }

  async getOrderByUserId(userId: number) {
    return this.prisma.$transaction(async (tx) => {
      const orders = await this.prisma.order.findMany({
        where: { user: { id: userId } },
        orderBy: { createdAt: 'desc' },
      });

      return Promise.all(
        orders.map(async (order) => {
          const products = await this.prisma.orderItem.findMany({
            where: { orderId: order.id },
            include: {
              menuItem: true,
            },
          });

          return {
            ...order,
            productCount: products.length,
            sum: products.reduce(
              (acc, item) =>
                acc + item.menuItem.price.toNumber() * item.quantity,
              0,
            ),
          };
        }),
      );
    });
  }

  async getOrderItems(orderId: number) {
    return this.prisma.$transaction(async (tx) => {
      const items = await this.prisma.orderItem.findMany({
        where: {
          orderId: orderId,
        },
        include: {
          menuItem: {
            select: {
              id: true,
              name: true,
              price: true,
              description: true,
            },
          },
        },
      });

      return items;
    });
  }
}

// ФАЙЛ: orders\dto\create.ts
 import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';

export const CreateOrderRequestSchema = z.object({
  address: z.string(),
  description: z.string().optional(),
  count: z.number().default(1),
  items: z.array(
    z.object({
      id: z.number(),
      quantity: z.number().default(1),
    }),
  ),
});

export type CreateOrderRequest = z.infer<typeof CreateOrderRequestSchema>;
export class CreateOrderDto extends createZodDto(CreateOrderRequestSchema) {}

// ФАЙЛ: prisma\prisma.module.ts
 import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Module({
    providers: [PrismaService],
    exports: [PrismaService],
})
export class PrismaModule {}

// ФАЙЛ: prisma\prisma.service.ts
 import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
    async onModuleInit() {
        await this.$connect();
    }

    async onModuleDestroy() {
        await this.$disconnect();
    }
}

// ФАЙЛ: shared\item.ts
 export default interface Item {
  id: number;
  name: string;
  description: string;
  price: number;
  photo: string;
  categoryId: number;
}

// ФАЙЛ: shared\user.ts
 export type UserClaims = {
  id: number;
  email: string;
  role: string;
};

// ФАЙЛ: users\users.controller.ts
 import { Controller, Get } from '@nestjs/common';
import { RequiredAuth } from 'src/auth/decorators/auth.decorator';
import { User } from 'src/auth/decorators/user.decorator';
import { UserClaims } from 'src/shared/user';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
  constructor(private readonly userService: UsersService) {}

  @Get()
  @RequiredAuth()
  async getMe(@User() { id }: UserClaims) {
    const user = await this.userService.findById(id);

    return { ...user, password: undefined };
  }
}

// ФАЙЛ: users\users.module.ts
 import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { PrismaModule } from 'src/prisma/prisma.module';
import { UsersController } from './users.controller';
import { JwtModule } from '@nestjs/jwt';

@Module({
  providers: [UsersService],
  imports: [PrismaModule, JwtModule],
  controllers: [UsersController],
  exports: [UsersService],
})
export class UsersModule {}

// ФАЙЛ: users\users.service.ts
 import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { UserCreateDto } from './dtos/signup';

@Injectable()
export class UsersService {
  constructor(private readonly prisma: PrismaService) {}

  async create(dto: UserCreateDto) {
    return this.prisma.user.create({
      data: {
        name: dto.name,
        phone: dto.phone,
        email: dto.email,
        password: dto.password,
        role: dto.role,
      },
    });
  }

  async findById(id: number) {
    return this.prisma.user.findUnique({
      where: { id },
    });
  }

  async findByEmail(email: string) {
    return this.prisma.user.findUnique({
      where: { email },
    });
  }
}

// ФАЙЛ: users\dtos\login.ts
 import { createZodDto } from "nestjs-zod";
import { z } from "zod";

export const UserLoginRequestSchema = z.object({
    email: z.string().email(),
    password: z.string(),
})

export const UserLoginResponseSchema = z.object({
    accessToken: z.string(),
})

export type UserLoginRequest = z.infer<typeof UserLoginRequestSchema>;
export type UserLoginResponse = z.infer<typeof UserLoginResponseSchema>;

export class LoginDto extends createZodDto(UserLoginRequestSchema) {}
// ФАЙЛ: users\dtos\signup.ts
 import { $Enums } from '@prisma/client';
import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';

export const UserCreateRequestSchema = z.object({
  name: z.string(),
  phone: z.string(),
  email: z.string().email(),
  password: z.string(),
  role: z.nativeEnum($Enums.Role).optional(),
});

export const UserCreateResponseSchema = z.object({
  accessToken: z.string(),
});

export type UserCreateRequest = z.infer<typeof UserCreateRequestSchema>;
export type UserCreateResponse = z.infer<typeof UserCreateResponseSchema>;

export class UserCreateDto extends createZodDto(UserCreateRequestSchema) {}

// ФАЙЛ: utils\date.ts
 export const getCurrentDate = () => {
  const currentDate = new Date();
  const localISOTime = new Date(
    currentDate.getTime() - currentDate.getTimezoneOffset() * 60000,
  ).toISOString();

  return localISOTime;
};

